﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tao.OpenGl;

namespace AvantGameMachine.Graphics
{
    public class Face : IRenderizableObject
    {
        private int nv = 0;          // nombre de vèrtexs de la cara
        private int ReservedVertex = 0;
        private PosVector[] taulav = null;     // vector d'índexs a la taula de vèrtexs
        private PosVector normal;     // normal de la cara
        private Material material = null;
        private Color[] color = null;

        public Face()
        {
        }

        public void SetNumVertex(int maxvert)
        {
        	taulav = new PosVector[maxvert];
        	nv=0;
            ReservedVertex = maxvert;
            color = new Color[ReservedVertex];
            SetAllColors(Color.White());
            material = new Material(ReservedVertex, null);
        }

        public void SetAllColors(Color c)
        {
            for (int i = 0; i < color.Length; i++)
                color[i] = c;
        }

        public Face CreateQuad(float _lenx,float _leny,float _lenz)
        {
            SetNumVertex(4);
            SetVertex(0, new PosVector(_lenx / 2, _leny / 2, _lenz / 2));
            SetVertex(1, new PosVector(_lenx / 2, -1 * (_leny / 2), _lenz / 2));
            SetVertex(2, new PosVector(-1 * (_lenx / 2), -1 * (_leny / 2), _lenz / 2));
            SetVertex(3, new PosVector(-1 * (_lenx / 2), _leny / 2, _lenz / 2));
            nv = 4;
            return this;
        }

        public Face CreateBox(float _lenx,float _leny,float _posz)
        {
            SetNumVertex(4);
            SetVertex(0, new PosVector(_lenx / 2, _leny / 2, _posz));
            SetVertex(1, new PosVector(_lenx / 2, -1 * (_leny / 2), _posz));
            SetVertex(2, new PosVector(-1 * (_lenx / 2), -1 * (_leny / 2), _posz));
            SetVertex(3, new PosVector(-1 * (_lenx / 2), _leny / 2, _posz));
            nv = 4;
            return this;
        }

        public int NumVertex
        {
            get { return ReservedVertex;  }
            set { ReservedVertex = value; }
        }

        public override PosVector Max
        {
            get
            {
                PosVector max = new PosVector(float.MinValue, float.MinValue, float.MinValue);
                for (int i = 0; i < nv; i++)
                {
                    if (taulav[i].X > max.X)
                    {
                        max.X = taulav[i].X;
                    }

                    if (taulav[i].Y > max.Y)
                    {
                        max.Y = taulav[i].Y;
                    }

                    if (taulav[i].Z > max.Z)
                    {
                        max.Z = taulav[i].Z;
                    }
                }

                return max;
            }
        }

        public override PosVector Min
        {
            get
            {
                PosVector min = new PosVector(float.MaxValue, float.MaxValue, float.MaxValue);
                for (int i = 0; i < nv; i++)
                {
                    if (taulav[i].X < min.X)
                    {
                        min.X = taulav[i].X;
                    }

                    if (taulav[i].Y < min.Y)
                    {
                        min.Y = taulav[i].Y;
                    }

                    if (taulav[i].Z < min.Z)
                    {
                        min.Z = taulav[i].Z;
                    }
                }

                return min;
            }
        }

        public PosVector GetVertex(int i)
        {
        	return taulav[i];
        }

        public void SetVertex(int i, PosVector v)
        {
        	taulav[i] = v;
        }

        public void addVertex(PosVector v)
        {
            taulav[nv] = v;
            nv++;
        }

        public PosVector Normal
        {
            get { return normal;  }
            set { normal = value; }
        }

        public void UpdateNormal()
        {
            float nx = 0;
            float ny = 0;
            float nz = 0;

            for (int i = 0; i < NumVertex; i++)
            {
                int j = i + 1;
                if (j >= NumVertex)
                    j = 0;

                PosVector iv = GetVertex(i);
                PosVector jv = GetVertex(j);

                nx += (iv.Z + jv.Z) * (iv.Y + jv.Y);
                ny += (iv.X + jv.X) * (iv.Z + jv.Z);
                nz += (iv.Y + jv.Y) * (iv.X + jv.X);
            }

            nx /= 2;
            ny /= 2;
            nz /= 2;

            PosVector temp = new PosVector(nx, ny, nz);
            temp.MakeUnit();
            Normal = temp;
        }

        public Material FaceMaterial
        {
            get { return material;  }
            set { material = value; }
        }

        public override void Render()
        {
            if (material != null)
            {
                if (material.MapTexture != null)
                {
                    Gl.glEnable(Gl.GL_TEXTURE_2D);
                    Gl.glBindTexture(Gl.GL_TEXTURE_2D, material.MapTexture.TextureID);
                }
            }

            Gl.glBegin(Gl.GL_POLYGON);   // pintem un polígon
            for (int k = 0; k < NumVertex; k++) // per cada vèrtex
            {
                PosVector v = GetVertex(k);
                if (material != null)
                {
                    Color c = material.GetColor(k);
                    Gl.glColor4f(c.R, c.G, c.B,c.A);
                    Gl.glTexCoord2f(material.GetVertex(k).X, material.GetVertex(k).Y);
                }
                else
                {
                    Color c = Color.White();
                    Gl.glColor4f(c.R, c.G, c.B, c.A);
                }
                Gl.glVertex3f(v.X, v.Y, v.Z);
            }
//            Gl.glNormal3f(Normal.X, Normal.Y, Normal.Z);

            Gl.glEnd();

            if (material != null)
            {
                if (material.MapTexture != null)
                {
                    Gl.glDisable(Gl.GL_TEXTURE_2D);
                }
            }
        }
    }
}
